package com.mall.group_booking.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mall.common.response.CommonResponse;
import com.mall.constant.enums.BookingRootStatus;
import com.mall.constant.enums.CommonStatus;
import com.mall.constant.enums.ConstantStatus;
import com.mall.constant.strings.ErrorMsg;
import com.mall.constant.strings.MapMsg;
import com.mall.constant.strings.SuccessMsg;
import com.mall.entity.groupbooking.GbRoot;
import com.mall.group_booking.entity.GbItemVo;
import com.mall.group_booking.entity.GbRecordVo;
import com.mall.group_booking.service.BookingRootService;
import com.mall.group_booking.service.BookingService;
import com.mall.utils.IdWorker;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author White
 * @version 1.0
 * @email 616769721@qq.com
 * @date 2021/7/30 17:30
 */
@Service
public class BookingServiceImpl implements BookingService {

    @Autowired
    private Redisson redisson;


    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Override
    public CommonResponse<Object> doBooking(GbRecordVo gbRecordVo) {
        //判断gbRecordVo.getUid()和gid是否为空
        if (gbRecordVo.getUid()==null || gbRecordVo.getItemId()==null){
            return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_PARAM_404);
        }
        //从redis中获取对应的map
        RMap<Long, GbItemVo> itemMap = redisson.getMap(MapMsg.BOOKING_ITEM_REDIS_MAP);
        RMap<Long, Integer> userMap = redisson.getMap(MapMsg.BOOKING_USER_REDIS_MAP+":"+gbRecordVo.getUid().toString());
        RMap<Long, GbRecordVo> recordMap = redisson.getMap(MapMsg.BOOKING_RECORD_REDIS_MAP);
        //对redisson上锁，钥匙为准备拼团的商品id
        RLock lock = redisson.getLock(gbRecordVo.getItemId().toString());
        try {
            lock.lock(5, TimeUnit.SECONDS);
            //获取缓存中的对应拼团商品
            GbItemVo gbItemVo = itemMap.get(gbRecordVo.getItemId());
            //判断商品是否存在
            if (gbItemVo==null||gbItemVo.getStatus().equals(ConstantStatus.CLOSE.getCode())){
                return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_PARAM_404);
            }
            //存在则判断是否卖完
            else if (gbItemVo.getLimitSurplus()<=0){
                return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_NUM_404);
            }
            //获取用户参与活动次数
            Integer participateCount = userMap.get(gbItemVo.getActivityId());
            //判断是否参与过
            if (participateCount!=null){
                //是否超过活动参与限定
                if (participateCount>=gbItemVo.getPayLimit()){
                    return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.MAXIMUM_NUMBER_OF_ACTIVITIES);
                }
            }else {
                participateCount=0;
            }
            //将数据放到map中
            HashMap<Object, Object> hashMap = new HashMap<>();
            hashMap.put("gbItemVo",gbItemVo);
            hashMap.put("gbRecordVo",gbRecordVo);
            //如果请求参数中包含团id
            if (gbRecordVo.getRootId()!=null){
                //redis中获取团map
                RMap<Integer, GbRoot> bookingRootMap = redisson.getMap(MapMsg.BOOKING_ROOT_REDIS_MAP);
                //根据团id上锁，同一团同时只有一个可操作
                RLock bookingRootMapLock = bookingRootMap.getLock(gbRecordVo.getRootId());
                try {
                    lock.lock(5,TimeUnit.SECONDS);
                    //从团map中获取该团对象
                    GbRoot gbRoot = bookingRootMap.get(gbRecordVo.getRootId());
                    //如果团对象为空，没取到
                    if (gbRoot==null){
                        return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_PARAM_404);
                    }
                    //判断团状态是否支持拼团并且团参与人数不超过限定
                    else if (gbRoot.getStatus().equals(BookingRootStatus.unfinished.getCode())&&gbRoot.getJoinCount()<gbItemVo.getCountPerson()){
                        //参与人数+1
                        gbRoot.setJoinCount(gbRoot.getJoinCount()+1);
                        //同步到redis中
                        bookingRootMap.put(gbRoot.getId(),gbRoot);
                        //设置拼团记录id
                        gbRecordVo.setId(new IdWorker().nextId());
                        gbRecordVo.setCreateTime(new Date());
                        //同步到redis
                        recordMap.put(gbRecordVo.getId(),gbRecordVo);
                        //异步同步到数据库
                        jmsMessagingTemplate.convertAndSend("doBookingRecord",JSONObject.toJSONString(hashMap));
                    }else {
                        return new CommonResponse<>(CommonStatus.UNVALID.getCode(), ErrorMsg.ERROR_NO_PRODUCT_ROOT_404);
                    }
                }finally {
                    bookingRootMapLock.unlock();
                }
            }
            //如果是开团请求
            else {
                //异步同步到数据库
                jmsMessagingTemplate.convertAndSend("doBookingRoot",JSONObject.toJSONString(hashMap));
            }
            //限量剩余-1
            gbItemVo.setLimitSurplus(gbItemVo.getLimitSurplus()-1);
            //参与人数+1
            gbItemVo.setPartIn(gbItemVo.getPartIn()+1);
            //同步到缓存
            itemMap.put(gbItemVo.getSpecItemId(),gbItemVo);
            //用户参与活动次数+1
            userMap.put(gbItemVo.getActivityId(),participateCount+1);
        }finally {
            lock.unlock();
        }
        return new CommonResponse<>(CommonStatus.VALID.getCode(), SuccessMsg.SUCCESS_CODE_200);
    }
}
